package demo2;

//抽象类：
//在面向对象的概念中，所有的对象都是通过类来描绘的，但是反过来，并不是所有的类都是用来描绘对象的，如果
//一个类中没有包含足够的信息来描绘一个具体的对象，这样的类就是抽象类。

//1.抽象类是被abstract修饰的
//2.被abstract修饰的方法，成为抽象方法，该方法可以没有具体的实现
//3.当一个类中含有抽象方法，该类必须使用abstract修饰（抽象类中不一定包含抽象方法，但是有抽象方法的类一定是抽象类）
//4.抽象类当中没有 可以有和普通类一样的成员变量和一样的成员方法
//5.抽象类是不可以被实例化的
//6.抽象类既然不能实例化对象，那么要抽象类来干什么？就是为了被继承
//7.当一个普通类继承了这个抽象类之后，这个普通类一定要重写这个抽象类的当中的所有的抽象方法
//8.final 和 abstract 两者不能同时存在，被abstract修饰的就是要被继承的与重写的，而final修饰的不能被重写和继承
//9.抽象类不能被private修饰，那么它的仅有抽象方法不能被private修饰
//10.抽象方法不能被static修饰，因为抽象方法要被子类重写
//11.当一个抽象类A不想被一个普通类B继承，此时可以把这个B类变成抽象类，那么在当一个普通类C继承这个抽象类B之后,C呀重写B和A的里面的所有抽象方法

abstract class Shape{
    public int a = 10;

    public void draw(){
        System.out.println("画图形");
    }
    public abstract void draw2();
    public void test(){

    }

    public Shape() {
        //既然它不能实例化，但是可以让子类调用帮助这个抽象类初始化它自己的成员
    }
}
class React extends Shape{
    @Override
    public void draw2() {
        System.out.println("矩形");
    }
}
class Flower extends Shape{
    @Override
    public void draw2() {
        System.out.println("花" );
    }
}

//当然不想重写方法，那么就把子类也变成了抽象类
abstract class A extends Shape{
    public abstract void testDemo();
}
//当然了，出来混，是迟早要还的
class  B extends A{
    @Override
    public void draw2() {

    }

    @Override
    public void testDemo() {

    }
    //所以B继承了A,A继承了父类，两个类都是抽象类，所以这个普通类就要重写两个方法
}
public class Test {
    public static void drawMap(Shape shape) {
        shape.draw2();
    }
    public static void main(String[] args) {
        //Shape shape = new Shape();//抽象类不能实例化
        Shape shape = new React();//向上转型，既然能发生向上转型，那么就能发生动态绑定，那么便是多态
        drawMap(new React());
        drawMap(new Flower());
        //new React() new Flower() 这种没有名字的对象 ---> 匿名对象
        //匿名对象的缺点：每次使用，都得去重新实例化
        //
    }

    //抽象类的作用：
    //抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类. 然后让子类重写抽象类中的抽象方法.

    /*
    有些同学可能会说了, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?
     */
    /*
    确实如此. 但是使用抽象类相当于多了一重编译器的校验.
    使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成. 那么此时如果不小心误用成父类了,
    使用普通类编译器是不会报错的. 但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题.

    意义：
    很多语法存在的意义都是为了 "预防出错", 例如我们曾经用过的 ﬁnal 也是类似. 创建的变量用户不去修改, 不
    就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们.
    充分利用编译器的校验, 在实际开发中是非常有意义的.
     */
}
